#include "testApp.h"

testApp::~testApp(){

    if(wave_view_data)
        delete[] wave_view_data;
    if(wave_L)
        delete[] wave_L;
    if(wave_R)
        delete[] wave_R;
}

//--------------------------------------------------------------
void testApp::Setup(){
   isPlaying = false;  // i wait on hitting "p" to play
   //clipSound.loadSound("sounds/sound1.wav");
   clipSound.loadSound("sounds/clip2.mp3");
   //clipSound.setLoop(true);

   playFiducialOnTheTable == false;

    path.xl=1;//left
    path.xr=0;//rigth
    path.yu=0;//up
    path.yd=1;//down

    y0 = ofGetHeight()/2;  // draw inside entire window, whatever size you want
    x0 = ofGetWidth()/8;
    w = ofGetWidth()-2*x0;
    h = y0/6;

    stereo = clipSound.getRawDataValues();

    wave_L = new short[clipSound.getSamplesLength()];
    wave_R = new short[clipSound.getSamplesLength()];

    max_Sound = 0;
    av_sound=0.0;
    int n=0;
    for(int i=0;i<2*clipSound.getSamplesLength();i+=2, n++)
    {
        wave_L[n]= stereo[i];
        wave_R[n]= stereo[i+1];
        av_sound= av_sound + std::abs(wave_R[n]) + std::abs(wave_L[n]);
        int current_max = std::max(abs(stereo[i]),abs(stereo[i+1]));
        if (max_Sound< current_max)
            max_Sound = current_max;
    }

    av_sound = av_sound/(clipSound.getSamplesLength());
    wave_view_data = new unsigned[3000];//to have an ample buffer
    memset(wave_view_data,0,3000);

    view_size=0;
    scale=1;
    shift = 0;
    make_circle = false;
    center_zoom = w/2;


	fftSmoothed = new float[8192];
	for (int i = 0; i < 8192; i++){
		fftSmoothed[i] = 0;
	}

	nBandsToGet = 512;

	playbackSpeed_previous = playbackSpeed_current = 1.0f;
	Pan_current = Pan_previous = 0.5f;
    Volume_current = Volume_previous = 1.0f;
}

int testApp::getSampleFromPixel(int x_pixel)
{
    float width = (float) scale*w / clipSound.getSamplesLength();
    float current_pixel;

    if(x_pixel<x0||x_pixel>ofGetWidth()-x0)
        return -1;// you cannot scale the image

    for (int x=0; x<view_size-1; x++)
    {
        current_pixel = x0 + offset*width*x/2;
       if(current_pixel>x_pixel)
       {
            //std::cout<<"x ="<<x<<endl;
            return wave_view_data[x-1];
       }

    }

}
//--------------------------------------------------------------
void testApp::Update()
{
   processTevents();//important to have TUIO callbacks!

	ofBackground(28,28,28);
    int length_samples = clipSound.getSamplesLength();
    float width = (float) scale*w / length_samples;
    offset = (int)floor(length_samples/(w*scale));
    if (offset%2>0)offset--; // forces an even number to stay within a channel (either R or L)
    if (offset<2)offset=2; //there is no more resolution than the Right or Left channel


    unsigned x=0;
    for (unsigned count = 0 + shift; count - shift <2*length_samples/scale; x++, count=count+offset)
    {
        if(count>2*length_samples)break;
        wave_view_data[x] = (count);
    }

    view_size=x;

   if(playFiducialOnTheTable == false)
   {
        if(isPlaying == true)
              {
                 clipSound.stop();
                 isPlaying = false;
              }
   }

    paquets = 0;



	// (5) grab the fft, and put in into a "smoothed" array,
	//		by taking maximums, as peaks and then smoothing downward
	float * val = ofSoundGetSpectrum(nBandsToGet);		// request 128 values for fft
	for (int i = 0;i < nBandsToGet; i++){

		// let the smoothed calue sink to zero:
		fftSmoothed[i] *= 0.96f;

		// take the max, either the smoothed or the incoming:
		if (fftSmoothed[i] < val[i]) fftSmoothed[i] = val[i];

	}
}

//--------------------------------------------------------------
void testApp::Draw(){

    int length_samples = clipSound.getSamplesLength();
    float width = (float) scale*w /length_samples;

    ofSetColor(0,0,255);
    //Spectrum lines
//    for(int k = 0; k < 512 ; k++)
//    {
//
//        ofLine(ofGetWidth()-(300+k),(spectrum_values[k]*ofGetHeight())+600,ofGetWidth()-(300+k),0);
//    }

	float width_fft = (float)(10*128) / nBandsToGet;
	for (int i = 0;i < nBandsToGet; i++){
		// (we use negative height here, because we want to flip them
		// because the top corner is 0,0)
		ofRect(250+i*width_fft,ofGetHeight()-200,width_fft,-(fftSmoothed[i] * 200));
	}

    make_circle=false;
    glDisable(GL_LINE_STIPPLE);
    if (length_samples/(w*scale)<0.02)make_circle=true;

    //drawing waveform
    for (int x=0; x<view_size-1; x++)
    {
        if (make_circle)
        {
            ofCircle(x0 + offset*width*x/2,y0 - ((stereo[wave_view_data[x]]*h/max_Sound)), 2);
            glLineStipple(1, 0x3F07);
            glEnable(GL_LINE_STIPPLE);
        }

        //ofSetColor(39,10,255);
        //ofSetLineWidth(1.5f);
        //ofLine(x0 + offset*width*x/2, y0 - ((stereo[wave_view_data[x]]*h/max_Sound)),x0 + offset*width*(x+1)/2, y0 - ((stereo[wave_view_data[x+1]]*h/max_Sound)));
        ofSetColor(255,157,7);
        ofSetLineWidth(1.0f);
        ofLine(x0 + offset*width*x/2, y0 - ((stereo[wave_view_data[x]]*h/max_Sound)),x0 + offset*width*(x+1)/2, y0 - ((stereo[wave_view_data[x+1]]*h/max_Sound)));
    }

    //Drawing Time Line
    ofSetColor(255,255,255);
    ofSetLineWidth(2.0f);
    float ini_wave = ((float)wave_view_data[0])/(2*length_samples);
    float end_wave = ((float)wave_view_data[view_size-1])/(2*length_samples);
    float playbackpos = clipSound.getPosition();

    //Current play position cursor
    if(isPlaying == true)
      {
            if (playbackpos>=ini_wave&&playbackpos<=end_wave)
                //ofCircle(x0 + (playbackpos-ini_wave)*scale*w,y0 - ((stereo[wave_view_data[(int)floor(playbackpos-ini_wave)]]/32768.0f)*h), 3);
                ofLine(x0 + (playbackpos-ini_wave)*scale*w, y0- h, x0 + (playbackpos-ini_wave)*scale*w, y0+h);
      }

    //Circle for play fiducial
    //ofEnableAlphaBlending();
    ofSetColor(255,157,7, 1.0f);
    ofCircle((f1_x*ofGetWidth())+5, (f1_y*ofGetHeight())+3, 40+50*fftSmoothed[3]);
    //ofDisableAlphaBlending();


 //Drawing possible cuts
    ofSetColor(255,255,255);
    ofSetLineWidth(1.5f);
    for(std::vector<v_cut>::iterator it=vector_cuts.begin();it!=vector_cuts.end();it++)
    {
        for(std::vector<float>::iterator it2=(*it).begin()+2;it2!=(*it).end();it2++)
        {

            float x1 = (*it2);
            float x0 = (*(it2-2));
            float y1 = (*++it2);
            float y0 = (*(it2-2));

            ofLine(x0*ofGetWidth(), y0*ofGetHeight(), x1*ofGetWidth(), y1*ofGetHeight());
        }
    }}

//--------------------------------------------------------------
void testApp::WindowResized(int w, int h){

}

void testApp::wait ( float seconds )
{
  clock_t endwait;
  endwait = clock () + seconds * CLOCKS_PER_SEC ;
  while (clock() < endwait) {}
}
//////////////////////////////
// GESTURES
//////////////////////////////

void testApp::newtap(double x, double y)
{
    /*
    double xpos= (x -0.125)*1.33;
    if(std::sqrt((xpos-0.5)*(xpos-0.5)+(y-0.5)*(y-0.5))>0.5)return;

    if(y< 0.5 + ((float)h)/(ofGetHeight())&& y> 0.5 - ((float)h)/(ofGetHeight()))
    {
            int x_pixel = (int)floor(x*ofGetWidth());

            int position = getSampleFromPixel(x_pixel);
            if (position==-1)
                return;
            float pct = (float)((float)position)/((float)2*clipSound.getSamplesLength());
            std::cout<<"pct= "<<pct<<endl;
            clipSound.setPosition(pct);

   }
   */
}

void testApp::newDoubletap(double x, double y)
{
    double xpos= (x -0.125)*1.33;
    if(std::sqrt((xpos-0.5)*(xpos-0.5)+(y-0.5)*(y-0.5))>0.5)return;
     if(y< 0.5 + ((float)h)/(ofGetHeight())&& y> 0.5 - ((float)h)/(ofGetHeight()))
    {
        view_size=0;
        scale=1;
        shift = 0;
        h = y0/6;
        vector_cuts.clear();
    }
}
void testApp::newDrag(double x,double y, float speedx, bool removed)
{

    //std::cout << "new drag: x" << x << " y: " << y << std::endl;
    //std::cout << "xpeed: " << speedx << std::endl;

    double xpos= (x -0.125)*1.33;
    if(std::sqrt((xpos-0.5)*(xpos-0.5)+(y-0.5)*(y-0.5))>0.5)return;

    if(y< 0.5 + ((float)h)/(ofGetHeight())&& y> 0.5 - ((float)h)/(ofGetHeight()))
    {
        //drawing the path square
        if(x<path.xl)
            path.xl=x;
        if(x>path.xr)
            path.xr=x;
        if(y<path.yd)
            path.yd=y;
        if(y>path.yu)
            path.yu=y;

        float w_path= std::abs(path.xl-path.xr);
        float h_path= std::abs(path.yu-path.yd);
       // std::cout<<"h/w="<<h_path/w_path<<endl;
        //std::cout<<"w/h="<<w_path/h_path<<endl;
        if ((w_path/h_path)>1.1)
        {
            vector_cuts.clear();
            float f_speed=std::abs(speedx);
            //f_speed = 1.5;
            if(removed)
            {
                path.xl=1;//left
                path.xr=0;//rigth
                path.yu=0;//up
                path.yd=1;//down

                for(;f_speed >= 0; f_speed-=0.001)
                {

                   if(speedx>=0)
                    {
                        int move = offset*8*scale;                        if(shift-move<0)shift=0;                        else shift-=move;
                    }
                    if(speedx<0)
                    {
                        int move = offset*8*scale;
                        if (shift<2*clipSound.getSamplesLength()-offset*4*8*scale)
                        shift+=move;
                    }

                    //  wait(1.0);
                }
            }
            else
            {
                if(speedx>=0)
                {
                    int move = offset*8*scale;                    if(shift-move<0)shift=0;                    else shift-=move;
                }
                if(speedx<0)
                {
                    int move = offset*8*scale;
                    if (shift<2*clipSound.getSamplesLength()-offset*4*8*scale)
                    shift+=move;
                }
            }
        }

        if ((h_path/w_path)>2.0)
        {
            cut.push_back(x);//first "x" component
            cut.push_back(y);//second "y" component
            if(removed)
            {
                vector_cuts.push_back(cut);
                cut.clear();
                path.xl=1;//left
                path.xr=0;//rigth
                path.yu=0;//up
                path.yd=1;//down
            }
        }

    }
    else
        cut.clear();
}


void testApp::newScale(float sc ,float x1, float x2, float y1, float y2)
{
    //std::cout << "Rotation:" << rotation << std::endl;
    //std::cout << "Scale:" << scale << std::endl;

    double xpos1= (x1 -0.125)*1.33;
    double xpos2= (x2 -0.125)*1.33;
    if((std::sqrt((xpos1-0.5)*(xpos1-0.5)+(y1-0.5)*(y1-0.5))>0.5)||
        (std::sqrt((xpos2-0.5)*(xpos2-0.5)+(y2-0.5)*(y2-0.5))>0.5))
            return;



    if(y1< 0.5 + ((float)h)/(ofGetHeight())&& y1> 0.5 - ((float)h)/(ofGetHeight())&&y2< 0.5 + ((float)h)/(ofGetHeight())&& y2> 0.5 - ((float)h)/(ofGetHeight()))
    {
        vector_cuts.clear();
        float w_path= std::abs(x1-x2);
        float h_path= std::abs(y1-y2);
        if (h_path<0.02)
        {

             float scale_aux =scale*(1 + sc);
             if (scale_aux>=1.0)
                scale = scale_aux;

//             if(!make_circle)//            {
//                float x = std::min(x1,x2)+std::abs(x1-x2)/2;
//                int x_pixel = (int)floor(x*ofGetWidth());//                int center_zoom = getSampleFromPixel(x_pixel);
//                if (center_zoom ==-1)//the x_pixel is not within the wave drawing space.
//                    return;
//                //std::cout<<" center_zoom = "<<center_zoom;//                int length_samples = clipSound.getSamplesLength();//                shift= (int) floor(center_zoom - (float)length_samples/scale);//               // std::cout<<" shift="<<shift*100/length_samples<<endl;
//                if (shift<0)shift=0;//                if (shift%2>0)//                    shift++;//            }
        }
        if (w_path<0.02)
        {

            int h_aux = h*(1 + sc);
            if(h_aux<ofGetHeight()&&h_aux>ofGetHeight()/30)
                h = h_aux;
        }
    }
}

////////////////////////////
//FIDUCIALS
//

void testApp::addTuioObject(int32 id, int32 f_id ,float xpos,float ypos, float angle, float xspeed,float yspeed,float rspeed,float maccel, float raccel)
{
    if(f_id == 1)
    {
     //std::cout << " ADD " << std::endl;
     playFiducialOnTheTable = true;
     id_1 = id;
     playbackSpeed_previous = playbackSpeed_current = 1.0f;
     clipSound.setSpeed(1.0f);

     //std::cout << idTable << std::endl;
    }

    if(f_id == 6)
    {
        id_6 = id;

    }

    if(f_id == 12)
    {
        id_12 = id;

    }
}

void testApp::removeTuioObject(int32 id)
{
    if(id == id_1)
    {
        //std::cout << "REMOVE " << std::endl;
        playFiducialOnTheTable = false;
        clipSound.setSpeed(1.0f);
    }

}

void testApp::updateTuioObject(int32 id, int32 f_id ,float xpos,float ypos, float angle, float xspeed,float yspeed,float rspeed,float maccel, float raccel)
{

    if (f_id==1)
    {
        if(playFiducialOnTheTable == true)
        {
            if(isPlaying == false)
              {
                 clipSound.play();
                 isPlaying = true;
              }

            float increment = angle/(2*PI) - playbackSpeed_previous;

            f1_x = xpos;
            f1_y = ypos;

            if(increment != -1.0f)
                playbackSpeed_current += increment;

            clipSound.setSpeed(playbackSpeed_current);
            playbackSpeed_current = playbackSpeed_previous;

            //std::cout << "Fiducial 1 " << std::endl;
            //std::cout << xpos << std::endl;
            //std::cout << ypos << std::endl;
        }

    }

     if (f_id==6)
    {
        float increment = angle/(2*PI) - Pan_previous;

        if(increment != -1.0f)
            Pan_current += increment;

        clipSound.setPan(Pan_current);
        Pan_current = Pan_previous;
    }

    if (f_id==12)
    {
        float increment = angle/(2*PI) - Volume_previous;

        if(increment != -1.0f)
            Volume_current += increment;

        clipSound.setVolume(Volume_current);
        Volume_current = Volume_previous;


    }

}



